import tkinter as tk
from tkinterdnd2 import 
from tkinter import filedialog, messagebox
from datetime import datetime
from PIL import Image, ImageTk
from tkcalendar import DateEntry
import json
import os

from tkinterdnd2 import DndManager

# 数据存储路径
DATA_FILE = "tasks.json"

# 使用DndManager添加拖放功能
dnd_manager = DndManager(window)

def save_data(tasks):
    try:
        with open(DATA_FILE, 'w') as file:
            json.dump(tasks, file)
    except Exception as e:
        messagebox.showerror("Error saving data", str(e))

def load_data():
    try:
        if os.path.exists(DATA_FILE):
            with open(DATA_FILE, 'r') as file:
                return json.load(file)
        else:
            return []
    except Exception as e:
        messagebox.showerror("Error loading data", str(e))
        return []


window = tk.Tk()
window.title("To Do List")
window.geometry("800x600")

columns = ["To_Do", "In Progress", "Done"]
frames = {}
for col in columns:
    frame = tk.Frame(window, relief=tk.RAISED, borderwidth=1)
    frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
    frames[col] = frame
    label = tk.Label(frame, text=col, bg='lightblue', font=('Arial', 12, 'bold'))
    label.pack(fill=tk.X)

def add_task(task_name, priority, due_date, image_path, dialog):
    try:
        if not task_name or not priority or not due_date:
            raise ValueError("you must enter all")
        create_card(frames["To_Do"], task_name, priority, due_date, image_path)
        save_tasks()  # 保存任务数据到JSON文件
        dialog.destroy()
    except ValueError as ve:
        messagebox.showerror("error", str(ve))
    except Exception as e:
        messagebox.showerror("unknown error", str(e))
        create_card(frames["To_Do"], task_name, priority, due_date, image_path)
        dialog.destroy()

def create_card_dialog():
    dialog = tk.Toplevel(window)
    dialog.title("Create New Task")
    dialog.geometry("400x300")

    task_name_var = tk.StringVar()
    priority_var = tk.StringVar(value="High")
    due_date_var = tk.StringVar(value=datetime.now().strftime('%Y-%m-%d'))
    image_path_var = tk.StringVar()

    task_name_label = tk.Label(dialog, text="Task Name:")
    task_name_label.pack(pady=5)
    task_name_entry = tk.Entry(dialog, textvariable=task_name_var)
    task_name_entry.pack(pady=5)

    priority_label = tk.Label(dialog, text="Priority:")
    priority_label.pack(pady=5)
    priority_options = ["High", "Medium", "Low"]
    priority_menu = tk.OptionMenu(dialog, priority_var, *priority_options)
    priority_menu.pack(pady=5)

    due_date_label = tk.Label(dialog, text="Due Date (YYYY-MM-DD):")
    due_date_label.pack(pady=5)
    due_date_entry = DateEntry(dialog, textvariable=due_date_var, date_pattern='yyyy-mm-dd')
    due_date_entry.pack(pady=5)

    def select_image():
        try:
            filename = filedialog.askopenfilename(title="Select Image", filetypes=[("Image Files", "*.png;*.jpg;*.jpeg;*.gif")])
            if filename:
                image_path_var.set(filename)
        except Exception as e:
            messagebox.showerror("Image Selection Error", str(e))

    def on_confirm():
        if not task_name_var.get() or not priority_var.get() or not due_date_var.get():
            messagebox.showerror("Input Error", "All fields are required.")
            return
        add_task(task_name_var.get(), priority_var.get(), due_date_entry.get_date().strftime('%Y-%m-%d'), image_path_var.get(), dialog)

    confirm_button = tk.Button(dialog, text="Confirm", command=on_confirm)
    confirm_button.pack(pady=10)
    select_image_button = tk.Button(dialog, text="Select Image", command=select_image)
    select_image_button.pack(pady=5)

def create_card(frame, task_name, priority, due_date, image_path):
    try:
        card_frame = tk.Frame(frame, relief=tk.RAISED, borderwidth=1, padx=10, pady=10)
        card_frame.pack(fill=tk.X, pady=5)

        task_label = tk.Label(card_frame, text=f"Task: {task_name}", anchor='w')
        task_label.pack(fill=tk.X)
        priority_label = tk.Label(card_frame, text=f"Priority: {priority}", anchor='w')
        priority_label.pack(fill=tk.X)
        due_date_label = tk.Label(card_frame, text=f"Due Date: {due_date}", anchor='w')
        due_date_label.pack(fill=tk.X)
        edit_button = tk.Button(card_frame, text="Edit", command=lambda: edit_task(card_frame, task_name, priority, due_date, image_path))
        edit_button.pack(anchor='s')
        delete_button = tk.Button(card_frame, text="Delete", command=lambda: delete_card(card_frame))
        delete_button.pack(anchor='s')
        created_time_label = tk.Label(card_frame, text=f"Created: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", anchor='w')
        created_time_label.pack(fill=tk.X)

        if image_path:
            try:
                img = Image.open(image_path)
                img = img.resize((100, 100))
                img = ImageTk.PhotoImage(img)
                image_label = tk.Label(card_frame, image=img)
                image_label.image = img
                image_label.pack()
            except Exception as e:
                messagebox.showerror("Error loading image", "The image file could not be opened or read.")
    except Exception as e:
        messagebox.showerror("Error creating card", str(e))

def delete_card(card_frame):
    try:
        card_frame.destroy()
    except Exception as e:
        messagebox.showerror("Error deleting card", str(e))

def edit_task(card_frame, current_task_name, current_priority, current_due_date, current_image_path):
    try:
        edit_dialog = tk.Toplevel(window)
        edit_dialog.title("Edit Task")
        edit_dialog.geometry("400x300")

        task_name_var = tk.StringVar(value=current_task_name)
        priority_var = tk.StringVar(value=current_priority)
        due_date_var = tk.StringVar(value=current_due_date)
        image_path_var = tk.StringVar(value=current_image_path)

        task_name_label = tk.Label(edit_dialog, text="Task Name:")
        task_name_label.pack(pady=5)
        task_name_entry = tk.Entry(edit_dialog, textvariable=task_name_var)
        task_name_entry.pack(pady=5)

        priority_label = tk.Label(edit_dialog, text="Priority:")
        priority_label.pack(pady=5)
        priority_options = ["High", "Medium", "Low"]
        priority_menu = tk.OptionMenu(edit_dialog, priority_var, *priority_options)
        priority_menu.pack(pady=5)

        due_date_label = tk.Label(edit_dialog, text="Due Date:")
        due_date_label.pack(pady=5)
        due_date_entry = DateEntry(edit_dialog, textvariable=due_date_var, date_pattern='yyyy-mm-dd')
        due_date_entry.pack(pady=5)

        def select_image():
            try:
                filename = filedialog.askopenfilename(title="Select Image", filetypes=[("Image Files", "*.png;*.jpg;*.jpeg;*.gif")])
                if filename:
                    image_path_var.set(filename)
            except Exception as e:
                messagebox.showerror("wrongly select picture", str(e))

        confirm_button = tk.Button(edit_dialog, text="Confirm", command=lambda: save_edits(card_frame, task_name_var.get(), priority_var.get(), due_date_entry.get_date().strftime('%Y-%m-%d'), image_path_var.get(), edit_dialog))
        confirm_button.pack(pady=10)
        select_image_button = tk.Button(edit_dialog, text="Select Image", command=select_image)
        select_image_button.pack(pady=5)
    except Exception as e:
        messagebox.showerror("Error editing task", str(e))

def save_edits(card_frame, new_task_name, new_priority, new_due_date, new_image_path, dialog):
    try:
        for widget in card_frame.winfo_children():
            if isinstance(widget, tk.Label) and widget.cget('text').startswith("Task:"):
                widget.config(text=f"Task: {new_task_name}")
            elif isinstance(widget, tk.Label) and widget.cget('text').startswith("Priority:"):
                widget.config(text=f"Priority: {new_priority}")
            elif isinstance(widget, tk.Label) and widget.cget('text').startswith("Due Date:"):
                widget.config(text=f"Due Date: {new_due_date}")
            elif isinstance(widget, tk.Label) and hasattr(widget, 'image'):
                if new_image_path:
                    try:
                        img = Image.open(new_image_path)
                        img = img.resize((100, 100))
                        img = ImageTk.PhotoImage(img)
                        widget.config(image=img)
                        widget.image = img
                    except Exception as e:
                        messagebox.showerror("Error loading image", "The image file could not be opened or read.")
        dialog.destroy()
    except Exception as e:
        messagebox.showerror("Error saving edits", str(e))
    dialog.destroy()
    save_tasks()  # 保存任务数据到JSON文件

def extract_task_data(widget):
    task_data = {}
    for child in widget.winfo_children():
        if isinstance(child, tk.Label):
            text = child.cget('text')
            if text.startswith('Task:'):
                task_data['name'] = text.split(': ')[1]
            elif text.startswith('Priority:'):
                task_data['priority'] = text.split(': ')[1]
            elif text.startswith('Due Date:'):
                task_data['due_date'] = text.split(': ')[1]
        # 假设图像路径可以通过某种方式获取，这里省略了具体实现
        # 实际上可能需要一个全局变量或类变量来跟踪图像路径
    return task_data

def save_tasks():
    try:
        tasks = []
        for frame in frames.values():
            for child in frame.winfo_children():
                if isinstance(child, tk.Frame):
                    task_data = {
                        'name': '',
                        'priority': '',
                        'due_date': '',
                        'image_path': '',
                    }
                    for widget in child.winfo_children():
                        if isinstance(widget, tk.Label):
                            text = widget.cget('text')
                            if text.startswith('Task:'):
                                task_data['name'] = text.split(': ')[1]
                            elif text.startswith('Priority:'):
                                task_data['priority'] = text.split(': ')[1]
                            elif text.startswith('Due Date:'):
                                task_data['due_date'] = text.split(': ')[1]
                        elif isinstance(widget, tk.PhotoImage):
                            # 假设你有一个方式获取图片路径
                            task_data['image_path'] = widget.file
                    tasks.append(extract_task_data(child))
        save_data(tasks)
    except Exception as e:
        messagebox.showerror("Error saving tasks", str(e))

def create_cards_from_data(data):
    try:
        for task in data:
            create_card(frames["To_Do"], task['name'], task['priority'], task['due_date'], task['image_path'])
    except Exception as e:
        messagebox.showerror("Error creating cards", str(e))

tasks_data = load_data()
create_cards_from_data(tasks_data)

# # 使用DndManager添加拖放功能
# dnd_manager = DndManager(window)

def on_drop(event):
    # 修复拖放逻辑
    target_frame = event.widget
    source_widget = event.drag_source_widget
    column_name = [col for col, frame in frames.items() if frame == target_frame][0]
    
    # 提取任务数据
    task_data = extract_task_data(source_widget)

    # 删除原卡片
    source_widget.destroy()

    # 在新列中创建卡片
    create_card(frames[column_name], task_data['name'], task_data['priority'], task_data['due_date'], task_data['image_path'])
    save_tasks()

    def extract_task_data(widget):
        task_data = {}
        for child in widget.winfo_children():
            if isinstance(child, tk.Label):
                text = child.cget('text')
                if text.startswith('Task:'):
                    task_data['name'] = text.split(': ')[1]
                elif text.startswith('Priority:'):
                    task_data['priority'] = text.split(': ')[1]
                elif text.startswith('Due Date:'):
                    task_data['due_date'] = text.split(': ')[1]
            # 假设图像路径可以通过某种方式获取，这里省略了具体实现
            # 实际上可能需要一个全局变量或类变量来跟踪图像路径
        return task_data

    # 假设源部件是一个Frame，我们将其数据保存到新的栏目
    task_data = {}
    for child in source_widget.winfo_children():
        if isinstance(child, tk.Label):
            text = child.cget('text')
            if text.startswith('Task:'):
                task_data['name'] = text.split(': ')[1]
            elif text.startswith('Priority:'):
                task_data['priority'] = text.split(': ')[1]
            elif text.startswith('Due Date:'):
                task_data['due_date'] = text.split(': ')[1]
        elif isinstance(child, tk.PhotoImage):
            task_data['image_path'] = child.file

    # 将任务数据添加到新的栏目
    tasks_data[column_name].append(task_data)
    save_data(tasks_data)

dnd_manager.bind("<Drop>", on_drop)

button = tk.Button(window, text="Create", command = create_card_dialog)
button.pack()

window.mainloop()